package com.novoda.runbuddy.view.overlay;

import java.util.ArrayList;
import java.util.List;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.RectF;
import android.location.Location;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.Projection;
import com.novoda.runbuddy.activity.CurrentRunMap;
import com.novoda.runbuddy.util.LocationUtils;

public class CurrentRunMapOverlay extends Overlay {

	private final android.graphics.Point	PIN_HOTSPOT			= new android.graphics.Point(5, 29);

	public CurrentRunMap					mapOfJogActivity	= null;
	//public DrivingDirection					drivingDirections	= null;

	private Bitmap							PIN_START			= null;
	private Bitmap							PIN_END				= null;
	private Projection						pixelCalculator;
	private int[]							prevScreenCoords;
	protected List<Location>				path				= new ArrayList<Location>();
	int[]									screenCoords		= { 0, 0 };
	private Canvas							canvas;
	boolean									firstInPath;
	boolean									first				= true;

	MapView									mapView;

	public CurrentRunMapOverlay(CurrentRunMap map, MapView mView, Bitmap startLocationImage, Bitmap endLocationImage) {

		mapOfJogActivity = map;
		mapView = mView;
		PIN_START = startLocationImage;
		PIN_END = endLocationImage;

		prevScreenCoords = new int[2];
	}

	@Override
	public void draw(Canvas canvas, MapView mapView, boolean shadow) {
		if (!shadow) {
			this.canvas = canvas;
			this.pixelCalculator = mapView.getProjection();

			LocationUtils.MapBoundsChecker boundsChecker = new LocationUtils.MapBoundsChecker(mapView);

			Location prevLocation = null;
			boolean lastPointOnMap = false;

			for (Location loc : path) {
				boolean onMap = boundsChecker.isLocationOnMap(loc);
				// if the current point is on the map, or if the last point is
				// on the map, then we draw the line.
				if (onMap || lastPointOnMap) {
					// If the last point was off the map, then prevScreenCoords
					// needs to be set so the line can be drawn correctly
					if ((!lastPointOnMap) && (prevLocation != null)) {
						prevScreenCoords = getPointOnMap((int) prevLocation.getLatitude(), (int) prevLocation.getLongitude());
					}
					screenCoords = getPointOnMap((int) loc.getLatitude(), (int) loc.getLongitude());

					// if prevLocation is null, this is the first point, so draw
					// it as such
					if (prevLocation == null) {
						drawFirstPoint(screenCoords[0], screenCoords[1]);
					} else {
						drawLineToPoint(screenCoords[0], screenCoords[1]);
					}
				}

				lastPointOnMap = onMap;
				prevLocation = loc;
			}

			dropPinMarker(canvas, PIN_START, screenCoords[0] - 3, screenCoords[1] + 20);
		}
	}
	
	public void drawFirstPoint(int lat, int longi) {
		dropPinMarker(canvas, PIN_END, lat, longi - 18);
		canvas.drawOval(new RectF(lat - 5, longi + 5, lat + 5, longi - 5), getJoggingPoint());

		prevScreenCoords[0] = lat;
		prevScreenCoords[1] = longi;
	}

	public void drawLineToPoint(int lat, int longi) {
		canvas.drawOval(new RectF(lat - 5, longi + 5, lat + 5, longi - 5), getJoggingPoint());
		canvas.drawLine(prevScreenCoords[0], prevScreenCoords[1], lat, longi, getJoggingPathPainter());

		prevScreenCoords[0] = lat;
		prevScreenCoords[1] = longi;
	}

	private Paint getJoggingPoint() {
		Paint paint = new Paint();
		paint.setAntiAlias(true);
		paint.setARGB(165, 156, 192, 36);
		paint.setStrokeWidth(3);
		paint.setStyle(Paint.Style.FILL_AND_STROKE);
		return paint;
	}

	private Paint getJoggingPathPainter() {
		Paint paint = new Paint();
		paint.setAntiAlias(true);
		paint.setARGB(165, 255, 0, 0);
		paint.setStrokeWidth(3);
		paint.setStyle(Paint.Style.FILL_AND_STROKE);
		return paint;
	}

	private int[] getPointOnMap(int lat, int longi) {
		GeoPoint point = new GeoPoint(lat, longi);
		int[] screenCoords = new int[2];
		Point t = pixelCalculator.toPixels(point, null);
		screenCoords[0] = t.x;
		screenCoords[1] = t.y;
		return screenCoords;
	}

	private void dropPinMarker(Canvas canvas, Bitmap image, int lat, int longi) {
		canvas.drawBitmap(image, lat - PIN_HOTSPOT.x, longi - PIN_HOTSPOT.y, getRoutePathPainter());
	}

	protected Paint getJourneyTimePainter() {
		Paint paint = new Paint();
		paint.setAntiAlias(true);
		paint.setARGB(255, 255, 255, 255);
		paint.setStrokeWidth(1);
		paint.setStyle(Paint.Style.FILL_AND_STROKE);
		paint.setTextSize(24);
		return paint;
	}

	protected Paint getJourneyDistPainter() {
		Paint paint = new Paint();
		paint.setAntiAlias(true);
		paint.setARGB(255, 255, 255, 255);
		paint.setStrokeWidth(1);
		paint.setStyle(Paint.Style.FILL_AND_STROKE);
		paint.setTextSize(16);
		return paint;
	}

	protected Paint getRoutePathPainter() {
		Paint paint = new Paint();
		paint.setAntiAlias(true);
		paint.setStrokeWidth(4);
		paint.setARGB(190, 113, 105, 252);
		paint.setStyle(Paint.Style.STROKE);
		return paint;
	}

	public void addLocationToPath(Location pointLocation) {
		path.add(pointLocation);
	}

	public void clearPath() {
		path.clear();
	}
}